using System.Text.Json;
using Microsoft.Extensions.Caching.Memory;
using PHMEE.VibrationDataGenerator.Utils;

namespace PHMEE.VibrationDataGenerator.Data;

public class VibDataCacheService
{
    private readonly IMemoryCache _memoryCache;
    private const string CacheKey = "VibDataCache";

    public VibDataCacheService(IMemoryCache memoryCache)
    {
        _memoryCache = memoryCache;

        // 在 Program.cs 中，应用启动时加载数据，不在这里加载数据
        // LoadData();
    }

    /// <summary>
    /// 启动应用时，加载数据并缓存
    /// </summary>
    /// <exception cref="Exception"></exception>
    public void LoadData()
    {
        var foldPath = Path.Combine(AppContext.BaseDirectory, "Data", "PumpDriveEnd");
        var filePaths = Directory.GetFiles(foldPath, "*.json");
        
        // filePaths = filePaths.Where(f => f.Contains("1659482030.json")).ToArray();
        
        var dataList = new List<VibDataModel>();

        foreach (var filePath in filePaths)
        {
            var json = File.ReadAllText(filePath);
            var data = JsonSerializer.Deserialize<VibDataModel>(json, new JsonSerializerOptions
            {
                PropertyNameCaseInsensitive = true
            });
            
            if (data is null)
            {
                throw new Exception("Failed to deserialize json data.");
            }
            
            // 由于建龙的加速度数据单位为 g，所以 data 数组每一项都乘 9.8f，得到单位为 m/s^2 的加速度数据
            data.AccX = data.AccX.Select(x => x * 9.8f).ToArray();
            data.AccXCoef = CoefUtils.CalculateMinCoef(data.AccX);
            
            data.AccY = data.AccY.Select(y => y * 9.8f).ToArray();
            data.AccYCoef = CoefUtils.CalculateMinCoef(data.AccY);
            
            data.AccZ = data.AccZ.Select(z => z * 9.8f).ToArray();
            data.AccZCoef = CoefUtils.CalculateMinCoef(data.AccZ);
            
            dataList.Add(data);
        }

        // 按时间戳排序并存入缓存
        var sortedDataList = dataList.OrderBy(d => d.Timestamp).ToList();
        _memoryCache.Set(CacheKey, sortedDataList);
    }

    // 获取按时间戳排序的数据
    private List<VibDataModel> GetOrderedData()
    {
        if (_memoryCache.TryGetValue(CacheKey, out List<VibDataModel>? sortedDataList))
        {
            if (sortedDataList is null)
            {
                throw new Exception("Failed to get data from cache.");
            }
            
            return sortedDataList;
        }
        else
        {
            throw new Exception("No data found in cache. Please load the data first.");
        }
    }

    // 创建一个 VibDataEnumerator 实例
    public VibDataEnumerator CreateDataEnumerator()
    {
        var dataList = GetOrderedData();
        return new VibDataEnumerator(dataList);
    }

    // 清除缓存
    public void ClearCache()
    {
        _memoryCache.Remove(CacheKey);
    }

    // 重新加载数据
    public void ReloadData()
    {
        ClearCache();
        LoadData();
    }
}

// 独立的数据枚举器
public class VibDataEnumerator
{
    private readonly List<VibDataModel> _dataList;
    private int _currentIndex;

    public VibDataEnumerator(List<VibDataModel> dataList)
    {
        _dataList = dataList;
        _currentIndex = 0;
    }

    // 获取下一个方向的数据，并根据需求循环
    public (long ts, float[] data, float coef, int freq) GetNextData(SernorStyleEnum direction)
    {
        var currentData = _dataList[_currentIndex];
        _currentIndex = (_currentIndex + 1) % _dataList.Count;

        // 目前的测试数据 freq 为 8000
        int freq = 8000;
        
        return direction switch
        {
            SernorStyleEnum.X => (currentData.Timestamp, currentData.AccX, currentData.AccXCoef, freq),
            SernorStyleEnum.Y => (currentData.Timestamp, currentData.AccY, currentData.AccYCoef, freq),
            SernorStyleEnum.Z => (currentData.Timestamp, currentData.AccZ, currentData.AccZCoef, freq),
            _ => throw new ArgumentOutOfRangeException(nameof(direction), "Invalid vibration data direction")
        };
    }
}

public class VibDataModel
{
    public long Timestamp { get; set; }
    
    public float Fs { get; set; }

    public float[] AccX { get; set; } = null!;
    public float AccXCoef { get; set; }
    
    public float[] AccY { get; set; } = null!;
    public float AccYCoef { get; set; }
    
    public float[] AccZ { get; set; } = null!;
    public float AccZCoef { get; set; }
}
